#pragma once

#include <utility>
#include <mutex>

namespace Hi
{
template<typename T>
class HiSingleton {
public:
	template<typename...Args>
	static T* create(Args&&... args) {
		if (instance != nullptr) {
			return instance;
		}
		std::lock_guard<std::mutex> locker(mutex);
		if (instance != nullptr) {
			return instance;
		}
		instance = new T(std::forward<Args>(args)...);
		return instance;
	}
	
	static T* get() {
		if (instance != nullptr) {
			return instance;
		}
		throw std::logic_error("the instance is not init, please initialize the instance first");
	}
	
	static void destory() {
		if (nullptr == instance) {
			return;
		}
		
		std::lock_guard<std::mutex> locker(mutex);
		if (nullptr == instance) {
			return;
		}
		
		delete instance;
		instance = nullptr;
	}
	
	HiSingleton() = delete;
	virtual ~HiSingleton() = delete;
	HiSingleton(const HiSingleton&) = delete;
	HiSingleton& operator = (const HiSingleton&) = delete;
private:
	static T* instance;
	static std::mutex mutex;
};
template<class T>T* HiSingleton::instance = nullptr;
}